iOS Privacy: Announcing InAppBrowser.com - see what JavaScript commands get injected through an in-app browser
Last week I published a report on the risks of mobile apps using in-app browsers. Some apps, like Instagram and Facebook, inject JavaScript code into third party websites that cause potential security and privacy risks to the user.
I was so happy to see the article featured by major media outlets across the globe, like TheGuardian and The Register, generated a over a million impressions on Twitter, and was ranked #1 on HackerNews for more than 12 hours. After reading through the replies and DMs, I saw a common question across the community:
TikTok's In-App Browser injecting code to observe all taps and keyboard inputs, which can include passwords and credit cards
âHow can I verify what apps do in their webviews?â
Introducing InAppBrowser.com, a simple tool to list the JavaScript commands executed by the iOS app rendering the page.
To try this this tool yourself:
- Open an app you want to analyze
- Share the url https://InAppBrowser.com somewhere inside the app (e.g. send a DM to a friend, or post to your feed)
- Tap on the link inside the app to open it
- Read the report on the screen
TikTok's In-App Browser injecting code to observe all taps and keyboard inputs, which can include passwords and credit cards
I started using this tool to analyze the most popular iOS apps that have their own in-app browser. Below are the results Iâve found.
For this analysis I have excluded all third party iOS browsers (Chrome, Brave, etc.), as they use JavaScript to offer some of their functionality, like a password manager. Apple requires all third party iOS browsers apps to use the Safari rendering engine WebKit
.
Important Note: This tool canât detect all JavaScript commands executed, as well as doesnât show any tracking the app might do using native code (like custom gesture recognisers). More details on this below.
Fully Open Source
InAppBrowser.com is designed for everybody to verify for themselves what apps are doing inside their in-app browsers. I have decided to open source the code used for this analysis, you can check it out on GitHub. This allows the community to update and improve this script over time.
iOS Apps that have their own In-App Browser
- Option to open in default browser: Does the app provide a button to open the currently shown link in the default browser?
- Modify page: Does the app inject JavaScript code into third party websites to modify its content? This includes adding tracking code (like inputs, text selections, taps, etc.), injecting external JavaScript files, as well as creating new HTML elements.
- Fetch metadata: Does the app run JavaScript code to fetch website metadata? This is a harmless thing to do, and doesnât cause any real security or privacy risks.
- JS: A link to the JavaScript code that I was able to detect. Disclaimer: There might be other code executed. The code might not be a 100% accurate representation of all JS commands.
App | Option to open in default browser | Modify page | Fetch metadata | JS | Updated |
---|---|---|---|---|---|
TikTok | âď¸ | Yes | Yes | .js | 2022-08-18 |
â | Yes | Yes | .js | 2022-08-18 | |
FB Messenger | â | Yes | Yes | .js | 2022-08-18 |
â | Yes | Yes | .js | 2022-08-18 | |
Amazon | â | None | Yes | .js | 2022-08-18 |
Snapchat | â | None | None | 2022-08-18 | |
Robinhood | â | None | None | 2022-08-18 |
Click on the Yes
or None
on the above table to see a screenshot of the app.
Important: Just because an app injects JavaScript into external websites, doesnât mean the app is doing anything malicious. There is no way for us to know the full details on what kind of data each in-app browser collects, or how or if the data is being transferred or used. This publication is stating the JavaScript commands that get executed by each app, as well as describing what effect each of those commands might have. For more background on the risks of in-app browsers, check out last weekâs publication.
Even if some of the apps above have green checkmarks, they might use the new WKContentWorld
isolated JavaScript, which Iâll describe below.
TikTok monitoring all keyboard inputs and taps
When you open any link on the TikTok iOS app, itâs opened inside their in-app browser. While you are interacting with the website, TikTok subscribes to all keyboard inputs (including passwords, credit card information, etc.) and every tap on the screen, like which buttons and links you click.
- TikTok iOS subscribes to every keystroke (text inputs) happening on third party websites rendered inside the TikTok app. This can include passwords, credit card information and other sensitive user data. (
keypress
andkeydown
). We canât know what TikTok uses the subscription for, but from a technical perspective, this is the equivalent of installing a keylogger on third party websites. - TikTok iOS subscribes to every tap on any button, link, image or other component on websites rendered inside the TikTok app.
- TikTok iOS uses a JavaScript function to get details about the element the user clicked on, like an image (
document.elementFromPoint
)
Here is a list of all JavaScript commands I was able to detect.
Update: TikTokâs statement, as reported per Forbes.com:
The company confirmed those features exist in the code, but said TikTok is not using them.
âLike other platforms, we use an in-app browser to provide an optimal user experience, but the Javascript code in question is used only for debugging, troubleshooting and performance monitoring of that experience â like checking how quickly a page loads or whether it crashes,â spokesperson Maureen Shanahan said in a statement.
The above statement confirms my findings. TikTok injects code into third party websites through their in-app browsers that behaves like a keylogger. However claims itâs not being used.
Instagram does more than just inserting pcm.js
Last weekâs post talked about how Meta injects the pcm.js
script onto third party websites. Meta claimed they only inject the script to respect the userâs ATT choice, and additional âsecurity and user featuresâ.
The code in question allows us to respect peopleâs privacy choices by helping aggregate events (such as making a purchase online) from pixels already on websites, before those events are used for advertising or measurement purposes.
â via this tweet
After improving the JavaScript detection, I now found some additional commands Instagram executes:
- Instagram iOS subscribes to every tap on any button, link, image or other component on external websites rendered inside the Instagram app.
- Instagram iOS subscribes to every time the user selects a UI element (like a text field) on third party websites rendered inside the Instagram app.
Here is a list of all JavaScript commands I was able to detect.
Note on subscribing: When I talk about âApp subscribes toâ, I mean that the app subscribes to the JavaScript events of that type (e.g. all taps). There is no way to verify what happens with the data.
Apps can hide their JavaScript activities from this tool
Since iOS 14.3 (December 2020), Apple introduced the support of running JavaScript code in the context of a specified frame and content world. JavaScript commands executed using this approach can still fully access the third party website, but canât be detected by the website itself (in this case a tool like InAppBrowser.com).
Use a WKContentWorld object as a namespace to separate your appâs web environment from the environment of individual webpages or scripts you execute. Content worlds help prevent issues that occur when two scripts modify environment variables in conflicting ways. [âŚ] Changes you make to the DOM are visible to all script code, regardless of content world.
This new system was initially built so that website operators canât interfere with JavaScript code of browser plugins, and to make fingerprinting more difficult. As a user, you can check the source code of any browser plugin, as you are in control over the browser itself. However with in-app browsers we donât have a reliable way to verify all the code that is executed.
So when Meta or TikTok want to hide the JavaScript commands they execute on third party websites, all theyâd need to do is to update their JavaScript runner:
// Currently used code by Meta & TikTok
self.evaluateJavaScript(javascript)
// Updated to use the new system
self.evaluateJavaScript(javascript, in: nil, in: .defaultClient, completionHandler: { _ in })
For example, Firefox for iOS already uses the new WKContentWorld system. Due to the open source nature of Firefox and Google Chrome for iOS itâs easy for us as a community to verify nothing suspicious is happening.
Especially after the publicity of last weekâs post, as well as this one, tech companies that still use custom in-app browsers will very quickly update to use the new WKContentWorld
isolated JavaScript system, so their code becomes undetectable to us.
Hence, it becomes more important than ever to find a solution to end the use of custom in-app browsers for showing third party content.
Valid use-cases for in-app webviews
There are many valid reasons to use an in-app browser, particularly when an app accesses its own websites to complete specific transactions. For example, an airline app might not have the seat selection implemented natively for their whole airplane fleet. Instead they might choose to reuse the web-interface they already have. If they werenât able to inject cookies or JavaScript commands inside their webview, the user would have to re-login while using the app, just so they can select their seat. Shoutout to Venmo, which uses their own in-app browser for all their internal websites (e.g. Terms of Service), but as soon as you tap on an external link, they automatically transition over to SFSafariViewController
.
However, there are data privacy & integrity issues when you use in-app browsers to visit non-first party websites, such as how Instagram and TikTok show all external websites inside their app. More importantly, those apps rarely offer an option to use a standard browser as default, instead of the in-app browser. And in some cases (like TikTok), there is no button to open the currently shown page in the default browser.
iOS Apps that use Safari
The apps below follow Appleâs recommendation of using Safari or SFSafariViewController
for viewing external websites. More context on SFSafariViewController
in the original article.
All apps that use SFSafariViewController
or Default Browser
are on the safe side, and there is no way for apps to inject any code onto websites, even with the new WKContentWorld
system.
App | Technology | Updated |
---|---|---|
SFSafariViewController | 2022-08-15 | |
SFSafariViewController | 2022-08-15 | |
Default Browser | 2022-08-15 | |
Slack | Default Browser | 2022-08-16 |
Google Maps | SFSafariViewController | 2022-08-15 |
YouTube | Default Browser | 2022-08-15 |
Gmail | Default Browser | 2022-08-15 |
Telegram | SFSafariViewController | 2022-08-15 |
Signal | SFSafariViewController | 2022-08-15 |
Tweetbot | SFSafariViewController | 2022-08-15 |
Spotify | Default Browser | 2022-08-15 |
Venmo | SFSafariViewController | 2022-08-15 |
Microsoft Teams | Default Browser | 2022-08-16 |
Microsoft Outlook | Default Browser or Edge | 2022-08-16 |
Microsoft OneNote | Default Browser | 2022-08-16 |
Twitch | Default Browser | 2022-08-16 |
What can we do?
As a user of an app
Most in-app browsers have a way to open the currently shown website in Safari. As soon as you land inside an in-app browser, use the Open in Browser
feature to switch to a safer browser. If that button isnât available, you will have to copy & paste the URL to open the link in the browser of your choice. If the app makes it difficult to even do that, you can tap & hold a link on the website and then use the Copy feature, which can be a little tricky to get right.
TikTok doesnât have a button to open websites in the default browser.
Update: According to some tweets, sometimes there is a way to open websites in the default browser.
Companies using in-app browsers
If youâre at a company where you have an in-app browser, use it only for your own pages and open all external links in the userâs default browser. Additionally, provide a setting to let users choose a default browser over an in-app browser experience. Unfortunately, these types of changes rarely get prioritized over features that move metrics inside of tech organizations. However, itâs so important for people to educate others on their team, and their managers, about the positive impact of making better security and privacy decisions for the user. These changes can be transparently marketed to users as an opportunity to build further trust.
Major tech companies
Itâs important to call out how much movement thereâs been in the privacy of data space, but itâs unclear how many of these changes have been motion vs. true progress for the industry and the user.
âMany tech companies take heat for âabusing their usersâ privacyâ, when in fact they try to balance out business priorities, great user experiences, and ensuring they are respecting privacy and user data. Itâs clear why companies were motivated to provide an in-app experience for external websites in the first place.
With the latest technology, companies can start to provide a smooth experience for the user, while respecting their privacy. Itâs possible for iOS or Android developers to move the privacy standards and responsibility to Apple & Google (e.g. stricter app reviews, more permission screens, etc.), however this is a much larger conversation where companies need to work together to define what standards should exist. We canât have one or two companies set the direction for the entire industry, since a solution needs to work for the large majority of companies. Otherwise, weâre left in a world where companies are forced to get creative on finding ways to track additional user data from any source possible, or define their own standards of whatâs best for user privacy, ultimately hurting the consumer and the product experience.â
â Hemal Shah
Technology-wise App-Bound Domains seems to be an excellent new WebKit feature making it possible for developers to offer a safer in-app browsing experience when using WKWebView
. As an app developer, you can define which domains your app can access (your own), and you wonât be able to control third party pages any more. To disable the protection, a user would have to explicitly disable it in the iOS settings app. However, at the time of writing, this system is not yet enabled by default.
FAQs for non-tech readers
- Can in-app browsers read everything I do online? Yes, if you are browsing through their in-app browser they technically can.
- Do the apps above actually steal my passwords, address and credit card numbers? No! I wanted to showcase that bad actors could get access to this data with this approach. As shown in the past, if itâs possible for a company to get access to data legally and for free, without asking the user for permission, they will track it.
- How can I protect myself? Whenever you open a link from any app, see if the app offers a way to open the currently shown website in your default browser. During this analysis, every app besides TikTok offered a way to do this.
- Are companies doing this on purpose? Building your own in-app browser takes a non-trivial time to program and maintain, significantly more than just using the privacy and user-friendly alternative thatâs already been built into the iPhone for the past 7 years. Most likely there is some motivation there for the company to track your activities on those websites.
- I opened InAppBrowser.com inside an app, and it doesnât show any commands. Am I safe? No! First of all, the website only checks for one of many hundreds of attack vectors: JavaScript injection from the app itself. And even for those, as of December 2020, app developers can completely hide the JavaScript commands they execute, therefore there is no way for us to verify what is actually happening under the hood.
Tags: ios, privacy, hijacking, sniffing, apps, browser, tiktok, keylogger | Edit on GitHub